#include <stdint.h>
#include <stdio.h>
#include "string.h"
int isspace( char c )
{
    char comp[] = { ' ', '\t', '\r', '\n', '\v', '\f' };
    const int len = 6;
    for ( int i=0; i<len; ++i )
    {
        if ( c == comp[i] )
            return 1;
    }
    return 0;
}
 
char tolower( char c )
{
    if ( c >= 'A' && c <= 'Z' )
        return ( c + 32 );
    return c;
}
 
 
// 在字符串s中查找 c 第一次出现的 位置。
// 找到: 返回指针位置; 未找到: 返回NULL
char * strchr( const char * s, int c )
{
    for ( ; *s != (char)c; ++s )
    {
        if ( *s == '\0' )
            return NULL; // 如果s已抵达尾部，为找到，返回NULL
    }
     
    return (char *)s; // 返回 c在s的指针位置
}
 
// 在字符串S中从末尾开始查找字符c, 找到则返回 字符串指针位置，未找到返回NULL
char * strrchr( const char * s, int c )
{
    const char * p = s + strlen( s ); // p 指向 s 的末端
    do {
        if ( *p == (char)c )
            return (char *)p; //       
    } while ( --p >= s );
     
    return NULL;
}
 
// 在字符串S中指定长度内查找字符C。
char * strnchr( const char * s, size_t count, int c )
{
    for ( ; count-- && *s != '\0'; ++s )
    {
        if ( *s == (char)c )
            return (char *)s;
    }
     
    return NULL;
}
 
// 搜索一个字符串 s2 在另一个字符串 s1 中的第一次出现
char * strstr( const char * s1, const char * s2 )
{
    size_t l1, l2;
    l2 = strlen( s2 );
     
    if ( !l2 )
        return (char *)s1;
    l1 = strlen( s1 );
    while ( l1 >= l2 )
    {
        l1--;
        if ( !memcmp( s1, s2, l2) )
            return (char *)s1;
        s1++;
    }
    return NULL;
}
 
// 从字符串s开头查找符合 accept 字符， 返回字符串s开头连续包含字符串 accept 内的字符数目。
// 如返回n，则代表 字符串s 开头连续有n个字符都属于字符串accept内的字符。
//char *str="Linux was first developed for 386/486-based pcs.";
//printf("%d\n",strspn(str,"Linux")); // 输出为 5
//printf("%d\n",strspn(str,"/-")); // 输出为 0
//printf("%d\n",strspn(str,"1234567890")); // 输出为 0
size_t strspn( const char * s, const char * accept )
{
    const char * p;
    const char * a;
    size_t count = 0;
     
    for ( p = s; *p != '\0'; ++p )
    {
        for ( a = accept; *a != '\0'; ++a ) // *p 逐个与 accept允许的字符串比对。
        {
            if ( *p == *a ) // 只要符合 accept，跳出accept循环，count+1
                break;
        }
        if ( *a == '\0' ) // 如果 accept 到了末尾，则表示出现第一个不符合accept的字符位置了。
            return count;
        ++count;
    }
    return count;
}
 
// 从字符串s开头查找符合 reject 字符， 返回字符串s 开头连续不含字符串 reject 内的字符数目
// 如返回n， 则代表字符串s 开头连续有n 个字符都不含字符串 reject 内的字符.
//char *str = "Linux was first developed for 386/486-based pcs. ";
//printf("%d\n", strcspn(str, " ")); // 输出 5 ;只计算到" "的出现, 所以返回"Linux"的长度
//printf("%d\n", strcspn(str, "/-")); // 输出 33 ; 计算到出现"/"或"－", 所以返回到"6"的长度
//printf("%d\n", strcspn(str, "1234567890")); // 输出 30 ; 计算到出现数字字符为止, 所以返回"3"出现前的长度
size_t strcspn( const char * s, const char * reject )
{
    const char * p;
    const char * r;
    size_t count = 0;
     
    for ( p = s; *p != '\0'; ++p )
    {
        for ( r = reject; *r != '\0'; ++r )
        {
            if ( *p == *r ) // 如果 *p 等于 *r， 则返回 长度
                return count;
        }
        ++count; // 2者不相等时，count+1
    }
     
    return count;
}
 
// 在字符串S1中 检验 S2串，当s2字符出线在s1中时，则停止检验，并返回该字符位置
// char *s = "12,3a,45"
// char *ptr = strpbrk(s, ","); // ptr = ,3a,45
char * strpbrk( const char * s1, const char * s2 )
{
    const char * sc1, * sc2;
    for ( sc1 = s1; *sc1 != '\0'; ++sc1 )
    {
        for ( sc2 = s2; *sc2 != '\0'; ++sc2 )
        {
            if ( *sc1 == *sc2 )     // 如果 在 s1 中找到符合 s2 的字符        
                return (char *)sc1; // 则直接返回该字符位置
        }
    }
    return NULL; // 未找到则返回 NULL
}
 
char * strsep( char **s, const char *ct )
{
    char * sbegin = *s;
    char * end;
     
    if ( *sbegin == NULL )
        return NULL;
     
    end = strpbrk( sbegin, ct ); // 在 sbegin 中 查找 ct 第一次出线的位置。
    if ( end ) // 找到了
        *end++ = '\0'; // 添加 结束符'\0'
     
    *s = end; // s指向了新的 开始位置
    return sbegin; 
}
 
// 跳过空白符
char * skip_spaces( const char * str )
{
    while ( isspace( *str) )
        ++str;
    return (char *)str;
}
 
// 跳过首尾的空白符
char * strim( char * s )
{
    size_t size;
    char * end;
     
    s = skip_spaces( s ); // 跳过空白符
    size = strlen( s ); // 计算 s 字符长度
    if ( !size ) // 长度为0，则直接返回s
        return s; // s = '\0'
     
    end = s + size - 1; // end 指向 s 字符串末尾
    while ( end >= s && isspace( *end ) ) // 跳过末尾的空白符
        end--;
    *( end + 1 ) = '\0'; // 设置下一位为 '\0'
     
    return s;
}
 
// 计算字符串s的长度. 以 '\0' 结尾
size_t strlen( const char * s )
{
    const char * sc;
    for ( sc = s; *sc != '\0'; ++sc )
        ; // nothing
    return sc - s;
}
 
 
// 比较指定长度的2个字符串， 不区分大小写
int strnicmp( const char * s1, const char * s2, size_t len )
{
    unsigned char c1, c2;
    if ( !len )
        return 0;
     
    do {
        c1 = *s1++;
        c2 = *s2++;
         
        if ( !c1 || !c2 ) // 如果其中一个为空
            break;
        if ( c1 == c2 ) // 相等，则继续比较下一个
            continue;
        c1 = tolower( c1 );
        c2 = tolower( c2 ); // 都转换为小写
        if ( c1 != c2 ) // 不相等
            break;
    } while ( --len ); // 在指定长度内比较
     
    return (int)c1 - (int)c2; // 跳出循环后，比较字符是否相等。
}
 
// 比较2个字符串， 不区分大小写。
int strcasecmp( const char * s1, const char * s2 )
{
    int c1, c2;
    do {
        c1 = tolower( *s1++ );
        c2 = tolower( *s2++ );
    } while ( c1 == c2 && c1 != '0' ); //
     
    return c1 - c2;
}
 
// 比较指定长度的2个字符串， 不区分大小写
int strncasecmp( const char * s1, const char * s2, size_t n )
{
    int c1, c2;
    do {
        c1 = tolower( *s1++ );
        c2 = tolower( *s2++ );
    } while ( ( --n > 0) && c1 == c2 && c1 != '0' ); //
     
    return c1 - c2;
}
 
// 字符串拷贝。 将 src 内容 拷贝到 dest 中。
// 这里不带长度，src 长度 大于 dest 长度，则会超出 存储范围。
char * strcpy( char * dest, const char * src )
{
    char * begin = dest; // 指向 目的存储空间 的 开始。
     
    while ( ( *dest++ = *src++) != '\0' ) // 逐字符保存内容。s
        ; // nothing
     
    return begin;
}
 
// 字符串拷贝。 将 src 指定长度的内容 拷贝到 dest 中。
char * strncpy( char  * dest, const char * src, size_t count )
{
    char * move = dest;
     
    while ( count )
    {
        if ( ( *move = *src ) != '\0' )
            src++;
        move++;
        count--;
    }
     
    return dest;
}
 
// 字符串拼接， 将 src 内容 拷贝到 dest 的后面
char * strcat( char * dest, const char * src )
{
    char * begin = dest;
     
    while ( *dest )
        dest++; //
         
    while ( ( *dest++ = *src++ ) != '\0' )
        ; // do nothing
     
    return begin;
}
 
// 字符串拼接， 将 src 指定长度的内容 拷贝到 dest 的后面
char * strncat( char * dest, const char * src, size_t count )
{
    char * begin = dest;
     
    while ( *dest )
        dest++; //
         
    while ( ( *dest++ = *src++ ) != '\0' )
    {
        if ( --count == 0 )
        {
            *dest= '\0';
            break;
        }
    }
        ; // do nothing
     
    return begin;
}
 
// 比较2个字符串。 返回值: 0, -1, 1
int strcmp( const char * s1, const char * s2 )
{
    unsigned char c1, c2;
     
    while ( 1 )
    {
        c1 = *s1++;
        c2 = *s2++;
        if ( c1 != c2)
            return ( c1 < c2 ) ? -1 : 1; // 不相等 返回 -1 1
        if ( !c1 ) // 如果c1 已抵达末尾
            break;
    }
     
    return 0; // 相等返回 0
}
 
// 指定长度的2个字符串比较。 返回 0 -1 1
int strncmp( const char * s1, const char * s2, size_t count )
{
    unsigned char c1, c2;
     
    while ( count )
    {
        c1 = *s1++;
        c2 = *s2++;
        if ( c1 != c2 )
            return ( c1 < c2 ) ? -1 : 1; // 不相等 返回 -1 1
        if ( !c1 )
            break;
         
        count--; // 长度减1
    }
     
    return 0; // 相等返回 0
}
 
// 将 s 内长度为count 的内容 用c 来初始化s
void * memset( void *s, int c, size_t count )
{
    char * xs = (char *)s;
    while ( count-- )
        *xs++ = c;
    return s;
}
 
// 将 src 内count长度内容 拷贝到 dest 中
void * memcpy( void * dest, const void * src, size_t count )
{
    char * tmp = (char *)dest;
    const char * s = (const char *)src;
    while ( count-- )
        *tmp++ = *s++;
     
    return dest;
}
 
// 比较 s1 s2大小， 返回一个整数
int memcmp( const void * s1, const void *s2, size_t count )
{
    const unsigned char * su1 = (const unsigned char *)s1;
    const unsigned char * su2 = (const unsigned char *)s2;
 
    int res = 0;
    for ( ; count > 0; ++su1, ++su2, --count )
    {
        if ( ( res = *su1 - *su2 ) != 0 ) // 不相等，则跳出循环。
            break;
    }
    return res;
}